use super::{
    handler::{BoxedServiceFactory, FnServiceFactory, FromRequest, Handler},
    request::{Request, ServiceRequest},
    response::Response,
    Method, Protocol,
};

pub struct Route {
    uri: &'static str,
    method: Method,
    protocol: Protocol,
    pub f: BoxedServiceFactory,
}

impl Route {
    pub fn check(&self, req: &Request) -> bool {
        req.uri().path().contains(self.uri)
            && req.protocol() == self.protocol
            && req.method() == self.method
    }
}

pub fn router_to<F, T>(uri: &'static str, method: Method, protocol: Protocol, f: F) -> Route
where
    F: Handler<T, Output = Result<Response, anyhow::Error>> + Send + Sync + 'static,
    T: FromRequest + Send,
{
    Route {
        f: Box::new(FnServiceFactory::new(move |req| {
            let handler = f.clone();
            let ServiceRequest { req, mut body } = req;
            async move {
                match T::from_request(&req, &mut body).await {
                    Err(_err) => match req.protocol() {
                        Protocol::Http1_1 => Ok(Response::http_ok()),
                        Protocol::Rtsp1_0 => Ok(Response::rtsp_ok(&req)),
                        _ => Ok(Response::http_ok()),
                    },
                    Ok(data) => handler.call(data).await,
                }
            }
        })),
        uri,
        method,
        protocol,
    }
}
